/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.performance;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Vector;

import cgl.narada.aggregator.NotifierNode;
import cgl.narada.performance.gui.TableView;
import cgl.narada.service.ServiceException;
import cgl.narada.transport.Link;
import cgl.narada.transport.LinkPerformanceData;
import cgl.narada.transport.MonitoredLink;
import cgl.narada.transport.TransportException;
import cgl.narada.transport.TransportHandler;
import cgl.narada.transport.TransportHandlerImpl;
import cgl.narada.transport.udp.UDPLink;
import cgl.narada.transport.udp.UDPLinkFactory;

/**
   This class ensures that the managed links send out performance packets at
   specified intervals.
   @author Shrideep Pallickara
   $Date$
   $Revision$
*/

public class MeasurementInitiator extends Thread {
  private long MeasurementInterval = 60;
  private Hashtable managedLinks;
  private String moduleName = "MesaurementInitiator: ";
  private String hostName="sierra.ucs.indiana.edu";
  private String userGroup="A";
  private boolean first=true;
  private boolean toRemoveTheLastLink=false;
  private static NotifierNode notifier;
  private static TransportHandler t_handler;
  private byte[] dataNugget =
  {cgl.narada.protocol.Protocol.PERFORMANCE_MEASUREMENT_INITIATE};
  private Object synchroObject;
  private TableView table=new TableView();
  private int counter=0;
  private boolean notifier_Debug=false;
  private boolean publisher_Debug=false;
  private boolean sync_Debug=false;
  private String messageText="/cgl/narada/perfdata";
  private MonitoringDataPublisher mon_data_publisher;

  public MeasurementInitiator() {
    managedLinks = new Hashtable();
    synchroObject = new Object();
    if (publisher_Debug){
      mon_data_publisher = new MonitoringDataPublisher(1234567);
      try {
        mon_data_publisher.initializeBrokerCommunications();
        mon_data_publisher.initializeProducerAndConsumer();
      }
      catch (ServiceException ex) {
      }
    }
    if (notifier_Debug) {
//      table.set();
//      table.display();
      Properties prop = new Properties();
      prop.put("TCPServerPort", "4000");
      prop.put("hostname", "sierra.ucs.indiana.edu");
      prop.put("portnum", "2000");
      notifier = new NotifierNode(prop, "tcp");
      notifier.sendRegistrationToAggregator();  //register to aggregation node.
    }
  }

//adds the link to the list. These links are the measuring links.
  public void addToListOfManagedLinks(Link link){
    String key = link.getLinkId();
    if (key == null) {
      System.out.println(moduleName + "LinkID associated with link is null");
      return;
    }
    //System.out.println("LinkID..:"+key);
    if (managedLinks.containsKey(key)) {
      System.out.println(moduleName + "LinkID already registered");
      return;
    }
    managedLinks.put(key, link);
    if (first){
      table.set();
      table.display();
    }
    first=false;
    if (managedLinks.size() == 1) {
      synchronized(synchroObject) {
	synchroObject.notify();
      }
    }
  }

//returns the list of managed(measuring) links.
  public Hashtable getLinks(){
    return managedLinks;
  }

//removes the link from the list.
  public void removeFromListOfManagedLinks(Link link) {
    String key = link.getLinkId();
    if (key == null) {
      System.out.println(moduleName + "LinkID associated with link is null");
      return;
    }
    if (!managedLinks.containsKey(key)) {
      System.out.println(moduleName + "LinkID NOT registered");
      return;
    }
    managedLinks.remove(key);
  }

//sets the measurement interval.
  public void setMeasurementInterval(long interval) {
    MeasurementInterval = interval;
  }


  /**it notifies the links to start measurement.
    this method is called by the thread in */
  private void notifyLinksToInitiateMeasurements() {
    Enumeration e = managedLinks.elements();
    while (e!=null && e.hasMoreElements()) {
        Link link = (Link) e.nextElement();
        try {
	  if (link instanceof MonitoredLink) {
	    MonitoredLink mLink = (MonitoredLink) link;
	    link.sendData(mLink.sendPerformancePackets());
	  }
        }
        catch (TransportException transEx) {
          System.out.println(moduleName + transEx);
        }
        /*end try-catch */
      }
      /*end while */
  }

  public void setTransportHandler(TransportHandler th){
    t_handler=th;
  }

//check if there are new links which are measuring and add them to
//the managed link
  public void checkNewLinks(){
    Hashtable links=new Hashtable();
    managedLinks=new Hashtable();
    links=t_handler.getRegisteredLinks(); //get all the links from transporthandler
    //System.out.println("size..:"+links.size());
    Enumeration e = links.elements();
    while (e!=null && e.hasMoreElements()) {
      Link _link = (Link) e.nextElement();
      if (_link.performanceGatheringEnabled()) {
        //System.out.println("enabled");
        addToListOfManagedLinks(_link);
      }
    }
    //System.out.println("Here"+links.size());
    //if (links.size()==0) table.dispose();
  }

//set all the links to monitor
 public void enableMonitoring(){

   Hashtable links=new Hashtable();
   links=t_handler.getRegisteredLinks(); //get all the links from transporthandler
   Enumeration e = links.elements();
   while (e!=null && e.hasMoreElements()) {
     Link _link = (Link) e.nextElement();
     //if multicast do not enable
     String type=_link.getLinkId().substring(0,3);
     if (type.equalsIgnoreCase("Mul")){
     }else
     _link.setPerformanceGathering(true);

   }
   table.set();
 }

//set all the links to monitor
 public void disableMonitoring(){

   Hashtable links=new Hashtable();
   links=t_handler.getRegisteredLinks(); //get all the links from transporthandler
   Enumeration e = links.elements();
   while (e!=null && e.hasMoreElements()) {
     Link _link = (Link) e.nextElement();
     _link.setPerformanceGathering(false);
   }
   table.dispose();

 }

  public void displayMetrics(){
    toRemoveTheLastLink=true;
    Enumeration e = managedLinks.elements();
    Vector values=new Vector();
    Vector v;
    String link_ID;
    while (e!=null && e.hasMoreElements()) {
      v=new Vector();
      Link link = (Link) e.nextElement();
      link_ID=link.getLinkId();
      if (link.getAllPerformanceData() == null){}
      else
      {
        LinkPerformanceData[] d = link.getAllPerformanceData();
        v.addElement(link_ID);
        for (int i = 0; i < d.length; i++) {
          String s=d[i].getParameterValue();
          v.addElement(getNumberWithPrecision(s));
        }
        values.addElement(v);

        ConvertToXML cnvx = new ConvertToXML(hostName, link_ID, userGroup, d);
        if (publisher_Debug){
          try {
            mon_data_publisher.publishEvent(cnvx.getXMLForm());
          }
          catch (ServiceException ex) {
          }
        }
        if (notifier_Debug){
//          ConvertToXML cnv = new ConvertToXML(hostName, link_ID, userGroup, d);
          notifier.postInfoToAggregator(cnvx.getXMLForm());
        }
        table.setMonitoringData(d, link_ID);
      }
    }/*end while */
     table.setValues(values);
     table.refresh();
   }//end displayMetrics

  public String getNumberWithPrecision(String s){
    String number="";
    int precision=0;
    int index=s.indexOf(".");
    if (index==-1) return s;
    number=s.substring(0, index);
    String afterPoint=s.substring(index+1);
    if (afterPoint.length()>2) precision=2;
      else precision=afterPoint.length();

    number=number+s.substring(index, index+1+precision);
    return number;
  }

  public boolean isThereAnyMeasuringLink(){
    if (managedLinks.isEmpty()){
      //System.out.println("empty");
      if (toRemoveTheLastLink){
        displayMetrics();
        toRemoveTheLastLink=false;
      }
      return false;
    }
    toRemoveTheLastLink=true;
    return true;
  }
  public void run() {
    while (true) {
      try {
          if(sync_Debug){
            if (managedLinks.size() == 0) {
              synchronized (synchroObject) {
                System.out.println(moduleName + "Getting ready to wait()");
                synchroObject.wait();
              }
            }
            /* end if*/
          }
	notifyLinksToInitiateMeasurements();
	if (isThereAnyMeasuringLink() ) {
          displayMetrics();
        }

        checkNewLinks();
        Thread.currentThread().sleep(MeasurementInterval);

      } catch (InterruptedException ie) {
	System.out.println(moduleName + ie);
      } /*end try-catch */
    } /*end while(true) */

  } /*end run() */

  public static void main(String[] args) {
    cgl.narada.protocol.Handler protocolHandler = null;
    TransportHandlerImpl transportHandler =
      new TransportHandlerImpl(protocolHandler);

    UDPLinkFactory udpFac = new UDPLinkFactory();
    udpFac.setTransportHandler(transportHandler);

    Properties prop = new Properties();
    prop.put("UDPListenerPort", "3000");
    udpFac.setLinkFactoryProperties(prop);
    try {
      udpFac.loadLinkFactoryServices();
    } catch (TransportException transEx) {
      transEx.printStackTrace();
    }
    udpFac.setTransportHandler(transportHandler);

    Properties props = new Properties();
    props.put("hostname", "sierra.ucs.indiana.edu");
    int portnum = 3000;
    MeasurementInitiator initiator = new MeasurementInitiator();

    props.put("portnum", portnum +"");
    try {
      Link l=udpFac.createLink(props);

      initiator.addToListOfManagedLinks(udpFac.createLink(props));
      initiator.addToListOfManagedLinks(l);
    } catch (TransportException transEx) {
      System.out.println(transEx);
    }

    initiator.start();
    initiator.setMeasurementInterval(500);
    Hashtable h=initiator.getLinks();
    Enumeration e = h.elements();
    UDPLink link = (UDPLink) e.nextElement();
    System.out.println(link.getLinkId());
/*
    try {
      Thread.currentThread().sleep(2000);

    } catch (InterruptedException ie) {
      System.out.println(ie);
    } /*end try-catch */


    while (link.getAllPerformanceData()==null){
    }
    LinkPerformanceData[] d=link.getAllPerformanceData();
    for(int i=0;i < d.length;i++) {
      System.out.println(d[i]);
      System.out.println("Value."+i+"..."+d[i].getParameterValue());
    }

  }


}
